﻿using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace OmniKits.Core
{
    public class DynamicXElement : DynamicObject
    {
#pragma warning disable 1591

        private XElement _Element;

        public DynamicXElement(XElement element)
        {
            _Element = element;
        }

        protected static string NormalizeName(string name)
        {
            return name.Trim();
        }

        protected bool GetNode(string name, out object result)
        {
            name = NormalizeName(name);

            if (name[0] == '@')
            {
                name = name.Substring(1);

                var attr = _Element.Attribute(name);

                if (attr == null)
                {
                    result = null;
                    return false;
                }

                result = attr.Value;
            }
            else
            {
                result = _Element.Elements(name).Select(e => new DynamicXElement(e)).ToArray();
            }

            return true;
        }

        public override bool TryConvert(ConvertBinder binder, out object result)
        {
            if (binder.Type == typeof(string))
            {
                result = ToString();
                return true;
            }

            return base.TryConvert(binder, out result);
        }

        public override string ToString()
        {
            return _Element.Value;
        }

        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
        {
            if (indexes.Length != 1)
                throw new ArgumentException();
            var name = indexes[0] as string;
            if (name == null)
                throw new ArgumentException();
            return GetNode(name, out result);
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            return GetNode(binder.Name, out result);
        }
    }
}
